//
//  BLFFmpegPlayer.swift
//  player_demo
//
//  Created by cgw on 2024/7/5.
//

import UIKit

/*
 * player_demo        需注释： import SGPlayer
 * BLPlayerFramework  需导入： import SGPlayer
 */

#if BLPLAYER_FRAMEWORK
import SGPlayer
#endif

/*
 基于SGPlayer的播放器
 优势：可解码全部格式
 缺点：内存占用较多
 */

class BLFFmpegPlayer: UIViewController, BLPlayerControlViewDelegate, SGFrameOutputDelegate {

    let player = SGPlayer()
    let controlView = BLPlayerControlView()
    
    var url: URL?
    var videoTitle: String?
    var playBeginTime: TimeInterval = 0

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
//        var mm = BLPLAYER_FRAMEWORK
//        print(mm)
        
        self.view.backgroundColor = .black
        self.setupPlayer()
        
        self.controlView.embedIn(self.view)
        self.controlView.delegate = self
        self.controlView.setupVideoTitle(self.videoTitle)
        
        
        self.player.videoRenderer().view = self.view
        self.player.videoRenderer().displayMode = .plane

        self.replay()
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        
        self.player.pause()
        self.frameOutput?.close()
        self.frameOutput?.delegate = nil
        
        self.controlView.delegate = nil
        self.controlView.removeFromSuperview()
        
        NotificationCenter.default.removeObserver(self)
    }
    
    deinit{
        NotificationCenter.default.removeObserver(self)
    }
    
    static func play(url: URL, title: String? = nil, from: UIViewController) {
        let vc = BLFFmpegPlayer()
        vc.url = url
        vc.videoTitle = title
        from.present(vc, animated: true)
    }
    
    func replay() {
        guard let url = url else {
            return
        }
        let asset = SGAsset(url: url)
        self.player.replace(with: asset)
        if self.playBeginTime > 0 {
            
            ///直接seek会存在问题，所以先播放在暂停，然后延时0.5秒后再seek
            ///先这么处理吧
            self.player.play()
            self.player.pause()
            DispatchQueue.main.asyncAfter(deadline: .now()+0.5, execute: {
                let ct = CMTime.init(seconds: Double(self.playBeginTime), preferredTimescale: 1000)
                self.player.seek(to: ct, toleranceBefor: .zero, toleranceAfter: .zero, result: {_,_ in 
                    self.player.play()
                })
            })
        }else{
            self.player.play()
        }
        
        if frameOutput == nil {
            frameOutput = BLFrameOutput.init(asset: asset)
            frameOutput?.delegate = self
            frameOutput?.open()
            
            //停用音频与字幕的帧
            frameOutput?.pause(.audio)
            frameOutput?.pause(.subtitle)
        }
    }
    
    func setupPlayer() {
        NotificationCenter.default.addObserver(self, selector: #selector(playerInfoChanged(_:)), name: NSNotification.Name.SGPlayerDidChangeInfos, object: self.player)
    }
    
    // MARK: - 通知
    @objc func playerInfoChanged(_ noti: Notification) {
        let timeInfo = SGPlayer.timeInfo(fromUserInfo: noti.userInfo)
        let stateInfo = SGPlayer.stateInfo(fromUserInfo: noti.userInfo)
        let actionInfo = SGPlayer.infoAction(fromUserInfo: noti.userInfo)
        
        if (( actionInfo.rawValue & SGInfoAction.time.rawValue ) != 0) {
            //总时长
            
            if( actionInfo.rawValue & SGInfoAction.timeDuration.rawValue ) != 0 {
                self.controlView.setPlayTime(0, totalTime: CMTimeGetSeconds(timeInfo.duration))
            }
            
            //播放进度
            if( actionInfo.rawValue & SGInfoAction.timePlayback.rawValue ) != 0 {
                
                //确保不是在seeking中
                let isSeeking = stateInfo.playback.rawValue & SGPlaybackState.seeking.rawValue
                if isSeeking == 0 && self.controlView.isDraggingSlider == false {
                    
                    self.controlView.setPlayTime(CMTimeGetSeconds(timeInfo.playback), totalTime: CMTimeGetSeconds(timeInfo.duration))
                }
            }
        }
        
        //播放状态
        if ( actionInfo.rawValue & SGInfoAction.state.rawValue ) != 0 {
            
            if (stateInfo.playback.rawValue & SGPlaybackState.finished.rawValue ) != 0 {
                //播放完成, 自动重播
                self.replay()
            }
            
            let isPlaying = (stateInfo.playback.rawValue & SGPlaybackState.playing.rawValue) != 0
            
            self.controlView.setIsPlaying(isPlaying)
        }
    }
    
    // MARK: - 获取某时刻的图片
    private var frameOutput: BLFrameOutput?
    func frameOutput(_ frameOutput: SGFrameOutput!, didOutputFrames frames: [SGFrame]!, needsDrop: (() -> Bool)!) {
        
        frameOutput.pause(.audio)
        frameOutput.pause(.subtitle)
        
        guard let frames = frames else { return }
        
        for fr in frames {
            if let fr = fr as? SGVideoFrame {
                //视频帧
                frameOutput.pause(.video)
                guard let img = fr.image() else {
                    print("frameOut帧 图片为空")
                    return
                }
                
                DispatchQueue.main.async {
                    BLDragProgressPreviewView.shared.setupImage(img)
                }
                
            }else{
                print("非视频帧")
            }
        }
    }
    
    func frameOutput(_ frameOutput: SGFrameOutput!, didChange capacity: SGCapacity, type: SGMediaType) {
        
    }
    
    func frameOutput(_ frameOutput: SGFrameOutput!, didChange state: SGFrameOutputState) {
        
    }
    
    // MARK: - BLControlViewDelegate
    func playerControlView(_ controlView: BLPlayerControlView, handlePlayBtn: UIButton) {
        let stateInfo = self.player.sstateInfo()
        
        let isPlaying = (stateInfo.playback.rawValue & SGPlaybackState.playing.rawValue) != 0
        if isPlaying {
            self.player.pause()
        }else{
            self.player.play()
        }
    }
    
    func playerControlView(_ controlView: BLPlayerControlView, handleBackBtn: UIButton) {
        if let c = self.parent as? BLPlayer {
            c.dismiss(animated: true)
        }else{
            self.dismiss(animated: true)
        }
    }
    
    func playerControlView(_ controlView: BLPlayerControlView, handleRateBtn: UIButton) {
        self.controlView.showSelectRateView(Float(self.player.rate)) { newRate in
            self.player.rate = Float64(newRate)
        }
    }
    
    func playerControlView(_ controlView: BLPlayerControlView, handleFullScreenBtn: UIButton) {
        
    }
    
    func playerControlView(_ controlView: BLPlayerControlView, handleSliderStart: UISlider) {
        
    }
    
    func playerControlView(_ controlView: BLPlayerControlView, handleSliderEnd: UISlider) {
        
        let timeInfo = self.player.timeInfo()
        
        let scale = Int64(timeInfo.playback.timescale)
        let ct = CMTimeGetSeconds(timeInfo.duration)*TimeInterval(handleSliderEnd.value)*TimeInterval(scale)

        let currentTime = CMTimeMake(value: Int64(ct), timescale: Int32(scale))

        print("开始定位时间：\(currentTime.value)")
        self.player.seek(to: currentTime, toleranceBefor: CMTime.zero, toleranceAfter: CMTime.zero) { ret, err in
            
            print("定位时间完成")
            self.controlView.isDraggingSlider = false
        }
    }
    
    func playerControlView(_ controlView: BLPlayerControlView, handleSliderOutEnd: UISlider) {
        print("handleSliderOutEnd")
    }
    
    func playerControlView(_ controlView: BLPlayerControlView, handleSliderValueChange: UISlider) {
        
    }
    
    func playerControlView(_ controlView: BLPlayerControlView, getImageFromDuration duration: TimeInterval, complete: @escaping (UIImage) -> Void) {
        
        guard let out = frameOutput else { return }
        
        let timeInfo = self.player.timeInfo()
        let curr = CMTime(seconds: duration, preferredTimescale: timeInfo.playback.timescale)
        
        out.seek(to: curr)
        
        if out.isStarted == false {
            out.start()
            self.frameOutput?.isStarted = true
        }else{
            out.resume(.video)
        }
    }
    
    func playerControlView(_ controlView: BLPlayerControlView, updatePlayRate rate: Double){
        self.player.rate = rate
    }
}

private class BLFrameOutput: SGFrameOutput{
    var isStarted = false
}
